package com.yanqu.road.server.gameplayer.module.activity.climbtower;

import com.alibaba.fastjson.JSON;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.args.ValueParamArgs;
import com.yanqu.road.entity.activity.climbtower.*;
import com.yanqu.road.entity.activity.climbtower.enums.eClimbTowerCellType;
import com.yanqu.road.entity.activity.climbtower.enums.eClimbTowerEventType;
import com.yanqu.road.entity.config.goods.GoodsInfo;
import com.yanqu.road.entity.config.goods.OpenGoodsBagResult;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eLogMoneyType;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.entity.log.LogClimbTowerDraw;
import com.yanqu.road.entity.log.LogClimbTowerFight;
import com.yanqu.road.entity.log.LogClimbTowerPower;
import com.yanqu.road.entity.log.LogClimbTowerUserUpgrade;
import com.yanqu.road.logic.bussiness.player.ClimbTowerActivityBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.helper.CalcPowerResult;
import com.yanqu.road.logic.helper.PowerHelper;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.pb.activity.ClimbTowerProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.climbtower.ClimbTowerMgr;
import com.yanqu.road.server.manger.config.GoodsBagMgr;
import com.yanqu.road.server.manger.config.GoodsMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.log.AutoLogMgr;
import com.yanqu.road.server.pb.ClimbTowerActivityPb;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;

public class ClimbTowerModule extends GeneralModule {

    private UserClimbTowerData userData;

    private LinkedList<UserClimbTowerTopClimbRecord> topClimbRecordList;

    public ClimbTowerModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        ActivityInfo activityInfo = ClimbTowerMgr.getActivityInfo();
        if (ActivityMgr.activityInShowTime(activityInfo)) {
            userData = ClimbTowerActivityBussiness.getUserClimbTowerData(player.getUserId(), activityInfo.getActivityId());
            topClimbRecordList = ClimbTowerActivityBussiness.getUserClimbTowerTopClimbRecordList(player.getUserId(), activityInfo.getActivityId(), GameConfig.CLIMB_TOWER_TOP_CLIMB_LOG_DEFAULT_MAX_COUNT);
        }
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        if(userData != null){
            if(userData.isInsertOption()){
                ClimbTowerActivityBussiness.addUserClimbTowerData(userData);
            } else if (userData.isUpdateOption()) {
                ClimbTowerActivityBussiness.updateUserClimbTowerData(userData);
            }
        }

        List<UserClimbTowerTopClimbRecord> tempRecordList = getRecordList();
        for (UserClimbTowerTopClimbRecord record : tempRecordList) {
            if (record.isInsertOption()) {
                ClimbTowerActivityBussiness.addUserClimbTowerTopClimbRecord(record);
            }
        }
        return true;
    }

    @Override
    public void afterLogin() {

        if (!SystemOpenMgr.systemOpen(player, eSystemId.ClimbTowerActivity.getValue())) {
            return;
        }

        syncConfig();

        syncUserData();

    }

    public void syncConfig() {

        ClimbTowerConfig config = ClimbTowerMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }

        ClimbTowerProto.ClimbTowerConfigSyncMsg.Builder configSync = ClimbTowerProto.ClimbTowerConfigSyncMsg.newBuilder();

        int userPassId = 0;
        if(userData != null){
            userPassId = userData.getEvent().getPassId();
        }
        buildPassCellTempList(config, configSync, userPassId, userData);

        configSync.addAllBossReward(ClimbTowerMgr.getBossRewardTempList());

        ClimbTowerActivityPb.buildOtherConfig(config, configSync);

        player.sendPacket(Protocol.U_CLIMB_TOWER_SYNC_CONFIG, configSync);
    }

    public void buildPassCellTempList(ClimbTowerConfig config, ClimbTowerProto.ClimbTowerConfigSyncMsg.Builder configSync, int userPassId, UserClimbTowerData userData) {
        //最多下发两个boss之间的数据,外加最多6层
        int showBossNum = 1;
        int showTopSix = config.getSkillUpnum();
        List<Integer> handledCellList = new ArrayList<>();
        if(userData != null){
            handledCellList = userData.getPreHandleList();
        }
        for (ClimbTowerLevelInfo levelInfo : config.getLevelInfoList()) {
            if(showBossNum <= 0 && configSync.getPassCount() >= showTopSix){
                break;
            }
            if(levelInfo.getId() < userPassId - 1){
                continue;
            }
            //展示到下一个boss阶段终止
            if(levelInfo.getId() > userPassId && levelInfo.getBossId() > 0){
                showBossNum--;
            }
            for (ClimbTowerProto.ClimbTowerPassCellTemp.Builder builder : ClimbTowerActivityPb.buildLevelConfig(levelInfo, config, handledCellList)) {
                configSync.addPass(builder);
            }
        }
    }

    /**
     * 同步玩家数据
     */
    public void syncUserData() {

        ClimbTowerConfig config = ClimbTowerMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return;
        }

        if(SystemOpenMgr.systemOpen(player, eSystemId.ClimbTowerActivity.getValue())){
            if(userData == null){
                initUserData();
            }
        }

        if(userData == null){
            return;
        }
        recoverUserEnergyPower();

        ClimbTowerRoleInfo roleInfo = config.getClimbTowerRoleInfo(userData.getExp());

        ClimbTowerProto.ClimbTowerDataSyncMsg.Builder syncMsg = ClimbTowerProto.ClimbTowerDataSyncMsg.newBuilder();
        ClimbTowerProto.ClimbTowerUserDataTemp.Builder builder = ClimbTowerActivityPb.buildUserData(userData, roleInfo, isInTopCell());
        syncMsg.setUserData(builder);
        player.sendPacket(Protocol.U_CLIMB_TOWER_SYNC_DATA, syncMsg);
    }

    /**
     * 初始化玩家数据
     */
    public synchronized void initUserData() {
        // 系统未解锁
        if (!SystemOpenMgr.systemOpen(player, eSystemId.ClimbTowerActivity.getValue())) {
            return;
        }

        // 没有活动
        if (!ActivityMgr.activityInShowTime(ClimbTowerMgr.getActivityInfo()) || ClimbTowerMgr.getConfig() == null) {
            return;
        }

        ActivityInfo activityInfo = ClimbTowerMgr.getActivityInfo();

        // 已经有数据了
        if (userData != null && userData.getActivityId() == activityInfo.getActivityId()) {
            return;
        }

        ClimbTowerConfig config = ClimbTowerMgr.getConfig();

        UserClimbTowerData tmpUserData = new UserClimbTowerData();
        tmpUserData.setActivityId(activityInfo.getActivityId());
        tmpUserData.setUserId(getUserId());
        tmpUserData.setLastRecoverPowerTime(System.currentTimeMillis());
        tmpUserData.setPower(config.getAuraMax());
        tmpUserData.setAbility(BigInteger.valueOf(config.getPlayerStrengthBegin()));
        tmpUserData.setInsertOption();

        userData = tmpUserData;

        if (null == topClimbRecordList) {
            topClimbRecordList = new LinkedList<>();
        } else {
            topClimbRecordList.clear();
        }

    }

    /**
     * 体力恢复
     */
    public void recoverUserEnergyPower() {
        if (userData == null || ClimbTowerMgr.getConfig() == null) {
            return;
        }
        int beforeVal = userData.getPower();
        ClimbTowerConfig config = ClimbTowerMgr.getConfig();
        CalcPowerResult calcPowerResult = PowerHelper.calcPower(userData.getLastRecoverPowerTime() / 1000,
                config.getAuraGetCd() , config.getAuraGetNum(), config.getAuraMax(), userData.getPower());

        userData.setPower(calcPowerResult.getCurPower());
        userData.setLastRecoverPowerTime(calcPowerResult.getLastRecoverTime() * 1000);

        if(beforeVal != userData.getPower()){
            AutoLogMgr.add(new LogClimbTowerPower(ClimbTowerMgr.getActivityId(), player.getUserId(), 2, beforeVal, userData.getPower() - beforeVal, userData.getPower()));
        }
    }

    /**
     * 爬塔
     * @param x 下一层通道（起始0）
     */
    public int climbTower(int x) {

        if (player.isRequestToFast()) {
            return GameErrorCode.E_REQUEST_TOO_FAST;
        }

        ClimbTowerConfig config = ClimbTowerMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        if(userData == null){
            return GameErrorCode.E_CLIMB_TOWER_LOCK;
        }

        synchronized (userData) {
            ClimbTowerCell cell = ClimbTowerMgr.getCell(userData.getEvent().getPassId(), userData.getEvent().getCell());
            ClimbTowerCell nextCell = ClimbTowerMgr.getNextCell(userData.getEvent().getPassId(), userData.getEvent().getCell());

            if (nextCell == null) {
                return GameErrorCode.E_CLIMB_TOWER_REACH_TOP;
            }

            if (cell != null) {
                eClimbTowerCellType cellType = eClimbTowerCellType.getCellType(cell.getCellType());
                eClimbTowerCellType nextCellType = eClimbTowerCellType.getCellType(nextCell.getCellType());
                if (cellType == null || nextCellType == null) {
                    return GameErrorCode.E_REQUEST_ARGUMENT_ERROR;
                }
                if (!eClimbTowerCellType.isConnected(cellType, userData.getEvent().getColIndex(), nextCellType, x)) {
                    return GameErrorCode.E_CLIMB_TOWER_NEXT_NOT_CONNECT;
                }
                if (cell.getCellNum() + 1 != nextCell.getCellNum()){
                    return GameErrorCode.E_REQUEST_ARGUMENT_ERROR;
                }
            }

            ClimbTowerEventResult result = new ClimbTowerEventResult();
            //事件处理
            ClimbTowerCellEvent event = nextCell.getEventList().get(x);
            eClimbTowerEventType eventType = eClimbTowerEventType.getType(event.getEventType());
            if (eventType == null) {
                return GameErrorCode.E_GAME_ERROR;
            }
            String beforeExp = userData.getExp().toString();
            String beforeAbility = userData.getAbility().toString();
            eLogMoneyType logType = eLogMoneyType.ClimbTowerActivity;
            ClimbTowerProto.ClimbTowerClimbRespMsg.Builder respMsg = ClimbTowerProto.ClimbTowerClimbRespMsg.newBuilder();
            boolean upgradeLv = false;
            boolean addCellNum = false;
            int beforeCellNum = userData.getCellNum();
            switch (eventType) {
                case Weapons:
                    if (!userData.getPreHandleList().contains(nextCell.getCellNum())) {
                        updateUserAbility(new BigInteger(event.getEventVal()).add(userData.getAbility()));
                    }
                    break;
                case Traps:
                    BigInteger newAbility = userData.getAbility().subtract(new BigInteger(event.getEventVal()));
                    if (newAbility.compareTo(BigInteger.ZERO) < 0) {
                        newAbility = BigInteger.ZERO;
                    }
                    updateUserAbility(newAbility);
                    break;
                case Treasures:
                    updateUserAbility(userData.getAbility().multiply(new BigInteger(event.getEventVal())));
                    break;
                case Division:
                    updateUserAbility(userData.getAbility().divide(new BigInteger(event.getEventVal())));
                    break;
                case Box:
                    //宝箱奖励
                    GoodsInfo goodsInfo = GoodsMgr.getGoodsById(Integer.valueOf(event.getEventVal()));
                    if (goodsInfo == null) {
                        return GameErrorCode.E_GOODS_NO_EXIST;
                    }
                    OpenGoodsBagResult openResult = GoodsBagMgr.getRandomGoods(goodsInfo.getGoodsId());
                    //全部是灵气
                    recoverUserEnergyPower();
                    BigInteger val = openResult.getReward().getCountByGoodsId(config.getAuraItemId());
                    int beforeVal = userData.getPower();
                    userData.setPower(val.intValue() + userData.getPower());
                    respMsg.setReward(PropertyHelper.parsePropertyToString(openResult.getReward()));
                    logType = eLogMoneyType.ClimbTowerActivityBoxEventReward;
                    if(val.compareTo(BigInteger.ZERO) > 0){
                        //体力获得
                        AutoLogMgr.add(new LogClimbTowerPower(userData.getActivityId(), player.getUserId(), 4, beforeVal, userData.getPower() - beforeVal, userData.getPower()));
                    }
                    break;
                case Monster:
                    if (userData.getAbility().compareTo(new BigInteger(event.getEventVal())) < 0) {
                        return GameErrorCode.E_CLIMB_TOWER_BEAT_MONSTER_FAILS;
                    }
                    userData.setCellNum(1 + userData.getCellNum());
                    //需要特殊处理，先设置
                    userData.getEvent().setPassId(nextCell.getPassId());
                    userData.getEvent().setColIndex(x);
                    addCellNum = true;
                    upgradeLv = addUserExp(userData, new BigInteger(event.getEventVal()), config);
                    if (cell != null) {
                        userData.getEvent().setPassId(cell.getPassId());
                    }
                    respMsg.setExp(event.getEventVal());
                    break;
                case Boss:
                    if (userData.getAbility().compareTo(new BigInteger(event.getEventVal())) < 0) {
                        return GameErrorCode.E_CLIMB_TOWER_BEAT_BOSS_FAILS;
                    }
                    //boss奖励
                    ClimbTowerLevelInfo levelInfo = config.getClimbTowerLevelInfo(userData.getEvent().getPassId());
                    if (levelInfo != null) {
                        result.setReward(levelInfo.getReward());
                        logType = eLogMoneyType.ClimbTowerActivityBossEventReward;
                    }
                    userData.setCellNum(1 + userData.getCellNum());
                    //需要特殊处理，先设置
                    userData.getEvent().setPassId(nextCell.getPassId());
                    userData.getEvent().setColIndex(x);
                    addCellNum = true;
                    upgradeLv = addUserExp(userData, new BigInteger(event.getEventVal()), config);
                    if (cell != null) {
                        userData.getEvent().setPassId(cell.getPassId());
                    }
                    respMsg.setExp(event.getEventVal());
                    break;
            }

            ClimbTowerProto.ClimbTowerConfigSyncMsg.Builder configSync = ClimbTowerProto.ClimbTowerConfigSyncMsg.newBuilder();
            respMsg.setUpgrade(upgradeLv);
            UserClimbTowerEvent userEvent = new UserClimbTowerEvent();
            userEvent.setColIndex(x);
            if (nextCell.getPassId() != userData.getEvent().getPassId()) {
                userEvent.setCell(0);
            } else {
                userEvent.setCell(1 + userData.getEvent().getCell());
            }
            userEvent.setPassId(nextCell.getPassId());
            if (!addCellNum) {
                userData.setCellNum(1 + userData.getCellNum());
            }
            userData.setEvent(userEvent);
            if (cell != null && cell.getPassId() != nextCell.getPassId()) {
                buildPassCellTempList(config, configSync, userData.getEvent().getPassId(), userData);
            }

            if (!StringUtils.isNullOrEmpty(result.getReward())) {
                respMsg.setReward(result.getReward());
                player.getModule(CurrencyModule.class).addCurrency(result.getReward(), eLogMoneyType.ClimbTowerActivity, logType);
            }
            respMsg.addAllPass(configSync.getPassList());
            respMsg.setRet(0);

            ClimbTowerRoleInfo roleInfo = config.getClimbTowerRoleInfo(userData.getExp());
            respMsg.setUserData(ClimbTowerActivityPb.buildUserData(userData, roleInfo, isInTopCell()));

            player.sendPacket(Protocol.U_CLIMB_TOWER_CLIMB, respMsg);

            player.notifyListener(eGamePlayerEventType.ClimbTowerCellNumCrossRank.getValue(), new ValueParamArgs(userData.getCellNum(), String.valueOf(userData.getAbility())));

            AutoLogMgr.add(new LogClimbTowerFight(ClimbTowerMgr.getActivityId(), player.getUserId(), beforeCellNum, event.getEventType(), event.getEventType(),
                    beforeAbility, userData.getAbility().toString(), event.getEventVal(), beforeExp, userData.getExp().toString(), result.getReward()));

        }
        return 0;
    }

    /**
     * 老虎机(炼妖)
     * @param type 0 一次；1 十次
     */
    public int draw(int type) {

        int times = 1;
        if(type == 1){
            times = 10;
        }

        ClimbTowerConfig config = ClimbTowerMgr.getConfig();
        if (config == null || !ActivityMgr.activityInShowTime(config.getActivityInfo())) {
            return GameErrorCode.E_ACTIVITY_OVER_TIME;
        }

        if(userData == null){
            return GameErrorCode.E_CLIMB_TOWER_LOCK;
        }

        recoverUserEnergyPower();

        //体力是否足够
        int needPower = times * config.getAuraCostNum();
        if(userData.getPower() < needPower){
            return GameErrorCode.E_CLIMB_TOWER_POWER_NO_ENOUGH;
        }

        Random random = new Random();

        int totalTimes = userData.getDrawTimes();

        List<ClimbTowerDrawResult> drawResultList = new ArrayList<>();

        for (int i = 0; i < times; i++) {
            ClimbTowerMultipleInfo drawInfo = config.randomClimbTowerDrawInfo();
            //保底盘面
            ClimbTowerMultipleInfo saveDrawInfo = config.getSaveDrawInfo(totalTimes);
            if(saveDrawInfo != null){
                drawInfo = saveDrawInfo;
            }
            totalTimes++;
            //生成盘面数据
            ClimbTowerDrawResult drawResult = generateElement(random, drawInfo, config);
            if(drawResult == null){
                return GameErrorCode.E_GAME_ERROR;
            }
            drawResultList.add(drawResult);
        }

        int beforePower = userData.getPower();
        userData.setPower(userData.getPower() - needPower);
        userData.setDrawTimes(times + userData.getDrawTimes());

        //灵气日志
        AutoLogMgr.add(new LogClimbTowerPower(ClimbTowerMgr.getActivityId(), player.getUserId(), 0, beforePower, needPower, userData.getPower()));
        String beforeAbility = userData.getAbility().toString();
        String beforeExp = userData.getExp().toString();

        //奖励
        Property reward = new Property();

        //基础积分
        int baseScore = times * config.getDrawScoreBase();

        ClimbTowerProto.ClimbTowerDrawRespMsg.Builder respMsg = ClimbTowerProto.ClimbTowerDrawRespMsg.newBuilder();
        ClimbTowerProto.ClimbTowerUploadDrawNoticeMsg.Builder noticeMsg = ClimbTowerProto.ClimbTowerUploadDrawNoticeMsg.newBuilder();
        StringBuilder panData = new StringBuilder();
        List<Integer> comboIdList = new ArrayList<>();
        for (ClimbTowerDrawResult drawResult : drawResultList) {
            calSingleDrawResultReward(config, reward, noticeMsg, drawResult);
            drawResult.getRewardBuilder().setScore(config.getDrawScoreBase());
            respMsg.addReward(drawResult.getRewardBuilder());
            panData.append(JSON.toJSONString(drawResult.getData())).append("|");
            comboIdList.add(drawResult.getRealMultipleId());
        }
        //积分
        reward.addProperty(config.getScoreItemId(), BigInteger.valueOf(baseScore));

        //成就   //奖励入背包
        getRewardAndCompleteTask(userData, reward, config, drawResultList);


        //查找最大盘面
        int maxDrawMultipleId = drawResultList.get(0).getRealMultipleId();
        int maxDrawIndex = 0;
        for (int i = 0; i < drawResultList.size(); i++) {
            ClimbTowerDrawResult drawResult = drawResultList.get(i);
            if(drawResult.getRealMultipleId() > maxDrawMultipleId){
                maxDrawMultipleId = drawResult.getRealMultipleId();
                maxDrawIndex = i;
            }
        }

        ClimbTowerDrawResult maxDrawResult = drawResultList.get(maxDrawIndex);
        respMsg.setComboId(maxDrawResult.getRealMultipleId());
        if(maxDrawResult.getMultipleInfo().getId() != maxDrawResult.getRealMultipleId()){
            ClimbTowerMgr.getLogger().info("---- comboId {} to {}", maxDrawResult.getMultipleInfo().getId(), maxDrawResult.getRealMultipleId());
        }
        for (int ele : maxDrawResult.getData()) {
            respMsg.addData(ele);
        }
        for (Map.Entry<Integer, Integer> entry : maxDrawResult.getElementMap().entrySet()) {
            ClimbTowerProto.ClimbTowerDrawTypeElementTemp.Builder builder = ClimbTowerProto.ClimbTowerDrawTypeElementTemp.newBuilder();
            builder.setEle(entry.getValue());
            builder.setType(entry.getKey());
            respMsg.addEle(builder);
        }

        respMsg.setRet(0);
        ClimbTowerRoleInfo roleInfo = config.getClimbTowerRoleInfo(userData.getExp());
        respMsg.setUserData(ClimbTowerActivityPb.buildUserData(userData, roleInfo, isInTopCell()));
        player.sendPacket(Protocol.U_CLIMB_TOWER_DRAW, respMsg);

        if(noticeMsg.getNoticeCount() > 0){
            noticeMsg.setActivityId(config.getActivityInfo().getActivityId());
            player.sendPacket(Protocol.C_CLIMB_TOWER_UPLOAD_DRAW_NOTICE, noticeMsg);
        }

        AutoLogMgr.add(new LogClimbTowerDraw(ClimbTowerMgr.getActivityId(), player.getUserId(), times, needPower, PropertyHelper.parsePropertyToString(reward),
                beforePower, userData.getPower(), beforeAbility, userData.getAbility().toString(), beforeExp, userData.getExp().toString(), baseScore, panData.toString(), comboIdList));

        return 0;
    }

    /**
     * 计算单次抽奖结果的奖励
     * @param config 配置
     * @param reward 总奖励
     * @param noticeMsg 播报
     * @param drawResult 抽奖结果
     */
    private void calSingleDrawResultReward(ClimbTowerConfig config, Property reward, ClimbTowerProto.ClimbTowerUploadDrawNoticeMsg.Builder noticeMsg, ClimbTowerDrawResult drawResult) {
        Property roundReward = new Property();
        Map<Integer, Integer> timesMap = new HashMap<>();
        ClimbTowerProto.ClimbTowerDrawRewardTemp.Builder rewardTemp = ClimbTowerProto.ClimbTowerDrawRewardTemp.newBuilder();
        rewardTemp.setAbility("0");
        rewardTemp.setLingQi(0);
        rewardTemp.setExp("0");
        for (Map.Entry<Integer, Integer> entry : drawResult.getElementMap().entrySet()) {
            int times = timesMap.getOrDefault(entry.getValue(), 0);
            timesMap.put(entry.getValue(), 1 + times);
            int baseType = entry.getKey();
            int ele = entry.getValue();
            ClimbTowerProto.ClimbTowerDrawTypeElementTemp.Builder typeElementTemp = ClimbTowerProto.ClimbTowerDrawTypeElementTemp.newBuilder();
            typeElementTemp.setEle(ele);
            typeElementTemp.setType(baseType);
            rewardTemp.addEle(typeElementTemp);
        }
        int maxAddition = 0;
        ClimbTowerRoleInfo roleInfo = config.getClimbTowerRoleInfo(userData.getExp());
        if(roleInfo == null){
            return;
        }
        int maxMultipleId = 0;
        for (Map.Entry<Integer, Integer> entry : timesMap.entrySet()) {
            //int baseType = entry.getKey();
            int ele = entry.getKey();
            //三连倍率
            int threeMultiple = config.getDrawThreeMultiple();
            //倍率千分比
            int addition = drawResult.getMultipleInfo().getValue();
            ClimbTowerMultipleInfo multipleInfo = config.getClimbTowerMultipleInfo(entry.getValue() + "");
            if(multipleInfo != null){
                addition = multipleInfo.getValue();
                if(multipleInfo.getId() > maxMultipleId){
                    maxMultipleId = multipleInfo.getId();
                }
            }
            if(addition > maxAddition){
                maxAddition = addition;
            }
            drawResult.getAdditionMap().put(ele, addition);
            //计算奖励倍数
            ClimbTowerEventInfo eventInfo = config.getEventInfoByTypes(1, ele);
            if(eventInfo == null){
                return;
            }
            BigInteger baseVal;
            if(ele == 1006){
                //灵气
                baseVal = BigDecimal.valueOf(addition * threeMultiple).multiply(new BigDecimal(eventInfo.getExParam()))
                        .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).toBigInteger();
                ClimbTowerMgr.getLogger().info("" + baseVal);
            }else {
                baseVal = BigDecimal.valueOf(addition * threeMultiple).multiply(new BigDecimal(eventInfo.getExParam())).multiply(new BigDecimal(roleInfo.getAddEffect()))
                        .divide(BigDecimal.valueOf(1000 * 1000), 0, BigDecimal.ROUND_UP).toBigInteger();
            }
            reward.addProperty(ele, baseVal);
            roundReward.addProperty(ele, baseVal);
            if(ele == 1005){
                rewardTemp.setExp(baseVal.add(new BigInteger(rewardTemp.getExp())).toString());
            }else if(ele == 1006){
                rewardTemp.setLingQi(baseVal.intValue() + rewardTemp.getLingQi());
            }else {
                rewardTemp.setAbility(baseVal.add(new BigInteger(rewardTemp.getAbility())).toString());
            }
        }
        drawResult.setRealMultipleId(Math.min(maxMultipleId, drawResult.getMultipleInfo().getId()));
        if(drawResult.getRealMultipleId() == 0){
            ClimbTowerMultipleInfo min = config.getMultipleInfoList().get(0);
            if(min != null){
                drawResult.setRealMultipleId(min.getId());
            }
        }
        //特殊处理
        if(drawResult.getMultipleInfo().getElementNumList().size() > 1 && drawResult.getAdditionMap().size() > 1){
            //整体comboId降级
            drawResult.setRealMultipleId(drawResult.getMultipleInfo().getId() + 1 - drawResult.getAdditionMap().size());
        }
        rewardTemp.setComboId(drawResult.getRealMultipleId());
        drawResult.setRewardBuilder(rewardTemp);
        //是否播报
        if(config.getClimbTowerMultipleInfo(drawResult.getRealMultipleId()).getIsNotice() == 1){
            buildNoticeUploadMsg(noticeMsg, maxAddition, roundReward);
        }
    }

    private void getRewardAndCompleteTask(UserClimbTowerData userData, Property reward, ClimbTowerConfig config, List<ClimbTowerDrawResult> drawResultList) {

        for (ClimbTowerDrawResult drawResult : drawResultList) {
            for (Map.Entry<Integer, Integer> entry : drawResult.getAdditionMap().entrySet()) {
                int ele = entry.getKey();
                int add = drawResult.getAdditionMap().get(ele) / 1000;
                userData.addRuneNum(ele, add);
            }
        }

        for (Map.Entry<Integer, Integer> entry : userData.getRuneNumMap().entrySet()) {
            if(entry.getKey() == 1001){
                player.notifyListener(eGamePlayerEventType.ClimbTowerGreenRuneAchievement.getValue(), entry.getValue());
            }else if(entry.getKey() == 1002){
                player.notifyListener(eGamePlayerEventType.ClimbTowerBlueRuneAchievement.getValue(), entry.getValue());
            }else if(entry.getKey() == 1003){
                player.notifyListener(eGamePlayerEventType.ClimbTowerPurpleRuneAchievement.getValue(), entry.getValue());
            }else if(entry.getKey() == 1004){
                player.notifyListener(eGamePlayerEventType.ClimbTowerOrangeRuneAchievement.getValue(), entry.getValue());
            }
        }


        BigInteger ability = reward.getCountByGoodsId(1001);
        ability = ability.add(reward.getCountByGoodsId(1002));
        ability = ability.add(reward.getCountByGoodsId(1003));
        ability = ability.add(reward.getCountByGoodsId(1004));
        if(ability.compareTo(BigInteger.ZERO) > 0){
            updateUserAbility(userData.getAbility().add(ability));
            ClimbTowerMgr.getLogger().debug("实力增加：{}", ability.toString());
        }

        BigInteger exp = reward.getCountByGoodsId(1005);
        if(exp != null && exp.compareTo(BigInteger.ZERO) > 0){
            addUserExp(userData, exp, config);
            ClimbTowerMgr.getLogger().debug("经验增加：{}", exp.toString());
        }

        BigInteger power = reward.getCountByGoodsId(1006);
        if(power != null && power.compareTo(BigInteger.ZERO) > 0) {
            recoverUserEnergyPower();
            int beforeVal = userData.getPower();
            userData.setPower(userData.getPower() + power.intValue());

            //灵气日志
            AutoLogMgr.add(new LogClimbTowerPower(ClimbTowerMgr.getActivityId(), player.getUserId(), 1, beforeVal, power.intValue(), userData.getPower()));
            ClimbTowerMgr.getLogger().debug("灵气增加：{}", power.toString());
        }

        Property bagProperty = new Property();
        BigInteger score = reward.getCountByGoodsId(config.getScoreItemId());
        bagProperty.addProperty(config.getScoreItemId(), score);
        userData.setScore(userData.getScore() + score.intValue());
        ClimbTowerMgr.getLogger().debug("积分增加：{}", score);
        if(!bagProperty.isNothing()){
            player.getModule(CurrencyModule.class).addCurrency(bagProperty, eLogMoneyType.ClimbTowerActivity, eLogMoneyType.ClimbTowerActivityDrawReward);
        }

    }

    /**
     * 加经验/处理上吸事件
     * @param userData 玩家数据
     * @param exp 经验
     */
    private boolean addUserExp(UserClimbTowerData userData, BigInteger exp, ClimbTowerConfig config) {
        boolean upgrade = false;
        int oLv = config.getClimbTowerRoleInfo(userData.getExp()).getLevel();
        String beforeExp = userData.getExp().toString();
        userData.setExp(userData.getExp().add(exp));
        int nLv = config.getClimbTowerRoleInfo(userData.getExp()).getLevel();
        if(oLv < nLv){
            int num = config.getSkillUpnum();
            for (ClimbTowerLevelInfo levelInfo : config.getLevelInfoList()) {
                if(levelInfo.getId() < userData.getEvent().getPassId()){
                    continue;
                }
                if(num == 0){
                    break;
                }
                for (ClimbTowerCell towerCell : levelInfo.getCellList()) {
                    if(num == 0){
                        break;
                    }
                    if(towerCell.getCellNum() >= userData.getCellNum()){
                        if(userData.getPreHandleList().contains(towerCell.getCellNum())){
                            num--;
                            continue;
                        }
                        for (int i = 0; i < towerCell.getEventList().size(); i++) {
                            ClimbTowerCellEvent event = towerCell.getEventList().get(i);
                            if(towerCell.getCellNum() == userData.getCellNum() && userData.getEvent().getColIndex() == i){
                                //当前已处理过的，不再加
                                continue;
                            }
                            if(event.getEventType() == eClimbTowerEventType.Weapons.getType()){
                                userData.addPreHandle(towerCell.getCellNum());
                                updateUserAbility(userData.getAbility().add(new BigInteger(event.getEventVal())));
                            }
                        }
                        num--;
                    }
                }
            }
            upgrade = true;
            player.notifyListener(eGamePlayerEventType.ClimbTowerCellNumCrossRank.getValue(),  new ValueParamArgs(userData.getCellNum(), String.valueOf(userData.getAbility())));

            //升级日志
            AutoLogMgr.add(new LogClimbTowerUserUpgrade(ClimbTowerMgr.getActivityId(), player.getUserId(), userData.getCellNum(), oLv, nLv, userData.getAbility().toString(),
                    userData.getAbility().toString(), beforeExp, userData.getExp().toString()));
        }
        return upgrade;
    }

    private void buildNoticeUploadMsg(ClimbTowerProto.ClimbTowerUploadDrawNoticeMsg.Builder noticeMsg, int maxMultipleAddition, Property roundReward) {
        ClimbTowerProto.ClimbTowerNoticeMsg.Builder builder = ClimbTowerProto.ClimbTowerNoticeMsg.newBuilder();
        builder.setServerId(GameServer.getInstance().getServerId());
        builder.setNickName(player.getUserInfo().getNickName());
        builder.setValue(maxMultipleAddition / 1000);
        builder.setReward(PropertyHelper.parsePropertyToString(roundReward));
        builder.setTime(System.currentTimeMillis());
        noticeMsg.addNotice(builder);
    }

    /**
     * 根据组合生成盘面元素
     * @param random  随机函数
     * @param multipleInfo  组合信息
     */
    private ClimbTowerDrawResult generateElement(Random random, ClimbTowerMultipleInfo multipleInfo, ClimbTowerConfig config) {
        ClimbTowerDrawResult result = new ClimbTowerDrawResult();
        result.setMultipleInfo(multipleInfo);
        int[] drawData = null;
        int lineNum = Integer.valueOf(multipleInfo.getParam());
        if(lineNum == 0){

            //无奖励
            drawData = ClimbTowerMgr.randomNoComboElement(config, random);

            //校验
            for (int i = 1; i < 6; i++) {
                int sameNum = 0;
                List<Integer> list = ClimbTowerMgr.getBaseTypeIdx(i);
                for (int k = 1; k < list.size(); k++) {
                    if(list.get(k).equals(list.get(0))){
                        sameNum++;
                    }
                }
                if(sameNum == list.size() - 1){
                    ClimbTowerMgr.getLogger().error("---------- comboId : {} has rewards", multipleInfo.getId());
                    return null;
                }
            }

        }else if(lineNum == 1) {
            try {
                //基础类型奖励
                //随机一种基础类型
                int baseType = random.nextInt(5) + 1;
                //随机一种元素
                int ele = ClimbTowerMgr.getRandomElement(config, new ArrayList<>(), random, multipleInfo);
                result.getElementMap().put(baseType, ele);

                drawData = ClimbTowerMgr.getBaseData(baseType, ele);
                ClimbTowerMgr.fillEmptyOrReplaceElement(drawData, config, true, random);
            }catch (Exception e){
                ClimbTowerMgr.getLogger().error(e.getMessage());
                return null;
            }

        } else {
            try {
                //随机元素个数
                int idx = RandomHelper.getRandomIndexByWeight(multipleInfo.getElementNumList(), random);
                int num = idx + 1;
                //先随机多个元素
                List<Integer> excludeList = new ArrayList<>();
                List<Integer> eleList = new ArrayList<>();
                for (int i = 0; i < num; i++) {
                    int randomElement = ClimbTowerMgr.getRandomElement(config, excludeList, random, multipleInfo);
                    if (randomElement > 0) {
                        eleList.add(randomElement);
                        excludeList.add(randomElement);
                    }
                }
                List<Integer> baseTypeList = new ArrayList<>();
                List<Integer> threeLine = new ArrayList<>();
                threeLine.add(1);
                threeLine.add(3);
                int excludeThree = threeLine.get(random.nextInt(threeLine.size()));
                int fourLine = random.nextInt(3) + 1;
                //i:线类型
                for (int i = 1; i < 6; i++) {
                    //需要两条线两个以上元素的，4、5类型不能出现
                    if (i > 3 && lineNum > 1 && num > 1) {
                        continue;
                    }
                    //3条线需要同一个元素的，1、3只能存在一个，不然可能是4条线都是同一元素
                    if(lineNum == 3 && num == 1 && i == excludeThree){
                        continue;
                    }
                    //4条线需要同一个元素的，不能同时出现1、2、3，不然就是5条线都是同一元素
                    if(lineNum == 4 && num == 1 && i == fourLine){
                        continue;
                    }
                    baseTypeList.add(i);
                }
                List<Integer> typeList = new ArrayList<>();
                while (typeList.size() < lineNum){
                    int typeIdx = random.nextInt(baseTypeList.size());
                    typeList.add(baseTypeList.remove(typeIdx));
                }
                //多个类型组合
                for (int i = 0; i < typeList.size(); i++) {
                    int element = getElement(eleList, i, random);
                    int[] data = ClimbTowerMgr.getBaseData(typeList.get(i), element);
                    if (drawData == null) {
                        drawData = data;
                    } else {
                        for (int k = 0; k < data.length; k++) {
                            //合并数据
                            if (data[k] != 0) {
                                drawData[k] = data[k];
                            }
                        }
                    }
                    result.getElementMap().put(typeList.get(i), element);
                }
                if (drawData == null) {
                    //
                    return result;
                }
                ClimbTowerMgr.fillEmptyOrReplaceElement(drawData, config, true, random);
            }catch (Exception e){
                ClimbTowerMgr.getLogger().error(e.getMessage());
                return null;
            }
        }
        result.setData(drawData);

        //ClimbTowerMgr.getLogger().debug("----- userId={}, comboId={}", player.getUserId(), multipleInfo.getId());
        //ClimbTowerMgr.getLogger().debug("| {} | {} | {} |", drawData[0], drawData[1], drawData[2]);
        //ClimbTowerMgr.getLogger().debug("| {} | {} | {} |", drawData[3], drawData[4], drawData[5]);
        //ClimbTowerMgr.getLogger().debug("| {} | {} | {} |", drawData[6], drawData[7], drawData[8]);

        for (Map.Entry<Integer, Integer> entry : result.getElementMap().entrySet()) {
            ClimbTowerMgr.getLogger().debug("TYPE {}, ELEMENT {}", entry.getKey(), entry.getValue());
        }

        return result;
    }

    private Integer getElement(List<Integer> eleList, int i, Random random) {
        if(i < eleList.size()) {
            return eleList.get(i);
        }
        int idx = random.nextInt(eleList.size());
        return eleList.get(idx);
    }

    /**
     * 使用体力石头
     * @param num 数量
     */
    public int useStone(int num) {

        if(userData == null){
            return GameErrorCode.E_CLIMB_TOWER_LOCK;
        }

        recoverUserEnergyPower();

        ClimbTowerConfig config = ClimbTowerMgr.getConfig();

        String consume = config.getAddAuraItemId() + "=" + num;

        GoodsInfo goodsInfo = GoodsMgr.getGoodsById(config.getAddAuraItemId());
        if(goodsInfo == null){
            return GameErrorCode.E_GOODS_NO_EXIST;
        }

        if(!player.getModule(CurrencyModule.class).removeCurrency(PropertyHelper.parseStringToProperty(consume), eLogMoneyType.ClimbTowerActivity, eLogMoneyType.ClimbTowerActivityStoneConsume)){
            return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
        }

        int beforeVal = userData.getPower();
        userData.setPower(userData.getPower() + num * goodsInfo.getParamList().get(0).intValue());

        ClimbTowerProto.ClimbTowerUseStoneGoodsRespMsg.Builder respMsg = ClimbTowerProto.ClimbTowerUseStoneGoodsRespMsg.newBuilder();
        respMsg.setPower(userData.getPower());
        respMsg.setLastRecoverPowerTime(userData.getLastRecoverPowerTime());
        respMsg.setRet(0);
        player.sendPacket(Protocol.U_CLIMB_TOWER_USE_STONE, respMsg);

        AutoLogMgr.add(new LogClimbTowerPower(ClimbTowerMgr.getActivityId(), player.getUserId(), 3, beforeVal, userData.getPower() - beforeVal, userData.getPower()));

        return 0;
    }

    public void addSpecialGoods(int goodsId, BigInteger value) {
        if(userData == null){
            return;
        }
        ClimbTowerConfig config = ClimbTowerMgr.getConfig();
        if(config == null){
            return;
        }
        if(goodsId == config.getExpItemId()){
            //加经验
            addUserExp(userData, value, config);
        }
        if(goodsId == config.getStrengthItemId()){
            //加实力
            updateUserAbility(userData.getAbility().add(value));
            player.notifyListener(eGamePlayerEventType.ClimbTowerCellNumCrossRank.getValue(), new ValueParamArgs(userData.getCellNum(), String.valueOf(userData.getAbility())));
        }
        if(goodsId == config.getAuraItemId()){
            //加灵气
            recoverUserEnergyPower();
            userData.setPower(userData.getPower() + value.intValue());
        }
        syncUserData();
    }

    public void testDraw(int times) {

        ClimbTowerConfig config = ClimbTowerMgr.getConfig();
        if(config == null){
            return;
        }
        int totalTimes = 0;
        Random random = new Random();
        List<ClimbTowerDrawResult> drawResultList = new ArrayList<>();
        for (int i = 0; i < times; i++) {

            ClimbTowerMultipleInfo drawInfo = config.randomClimbTowerDrawInfo();

            //保底盘面
            ClimbTowerMultipleInfo saveDrawInfo = config.getSaveDrawInfo(totalTimes);
            if(saveDrawInfo != null){
                drawInfo = saveDrawInfo;
            }
            totalTimes++;

            //生成盘面数据
            ClimbTowerDrawResult drawResult = generateElement(random, drawInfo, config);
            if(drawResult == null){
                continue;
            }
            drawResultList.add(drawResult);
        }

        //奖励
        Property reward = new Property();

        //基础积分
        int baseScore = times * config.getDrawScoreBase();

        ClimbTowerProto.ClimbTowerUploadDrawNoticeMsg.Builder noticeMsg = ClimbTowerProto.ClimbTowerUploadDrawNoticeMsg.newBuilder();
        Map<Integer, Integer> comboMap = new HashMap<>();
        for (ClimbTowerDrawResult drawResult : drawResultList) {
            calSingleDrawResultReward(config, reward, noticeMsg, drawResult);
            int comboNum = comboMap.getOrDefault(drawResult.getMultipleInfo().getId(), 0);
            comboMap.put(drawResult.getRealMultipleId(), comboNum + 1);
        }
        //积分
        reward.addProperty(config.getScoreItemId(), BigInteger.valueOf(baseScore));

        ClimbTowerProto.ClimbTowerDrawTestRespMsg.Builder respMsg = ClimbTowerProto.ClimbTowerDrawTestRespMsg.newBuilder();
        //ele sum
        Map<Integer, Integer> sumMap = new HashMap<>();
        for (ClimbTowerDrawResult drawResult : drawResultList) {
            for (Map.Entry<Integer, Integer> entry : drawResult.getAdditionMap().entrySet()) {
                int ele = entry.getKey();
                int add = drawResult.getAdditionMap().get(ele) / 1000;
                int num = sumMap.getOrDefault(entry.getValue(), 0);
                sumMap.put(entry.getValue(), add + num);
            }
        }

        for (Map.Entry<Integer, Integer> entry : sumMap.entrySet()) {
            ClimbTowerProto.ClimbTowerTestRuneTemp.Builder builder = ClimbTowerProto.ClimbTowerTestRuneTemp.newBuilder();
            builder.setEventId(entry.getKey());
            builder.setNum(entry.getValue());
            //todo
            builder.setAbility("0");
            respMsg.addEvent(builder);
        }

        respMsg.setReward(PropertyHelper.parsePropertyToString(reward));

        player.sendPacket(Protocol.U_CLIMB_TOWER_DRAW_TEST, respMsg);
    }

    public UserClimbTowerData getUserData() {
        return userData;
    }

    /**
     * 判断是否在最高层
     */
    public boolean isInTopCell() {
        if (null == userData) {
            return false;
        }
        ClimbTowerCell nextCell = ClimbTowerMgr.getNextCell(userData.getEvent().getPassId(), userData.getEvent().getCell());
        if (nextCell != null) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * 新幻境爬塔结算
     */
    public void topCellClimbSettle(ClimbTowerProto.CrossClimbTowerTopClimbRespMsg crossMsg, UserClimbTowerTopClimbRecord record) {
        int newTopCell = crossMsg.getRetClient().getNewTopCell();
        String reward = crossMsg.getRetClient().getReward();
        synchronized (userData) {
            if (newTopCell > userData.getMaxTopCell()) {
                userData.setMaxTopCell(newTopCell);
            }
            if (newTopCell != userData.getTopCellNum()) {
                userData.setTopCellNum(newTopCell);
            }
        }
        if (!StringUtils.isNullOrEmpty(reward)) {
            player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.ClimbTowerActivity, eLogMoneyType.ClimbTowerActivityMaxTopCellChange);
        }

        addTopCellClimbRecord(record);
    }

    public List<UserClimbTowerTopClimbRecord> getRecordList() {
        List<UserClimbTowerTopClimbRecord> tempRecordList = new ArrayList<>();
        if (null != topClimbRecordList) {
            synchronized (topClimbRecordList) {
                tempRecordList = new ArrayList<>(topClimbRecordList);
            }
        }
        return tempRecordList;
    }

    public void addTopCellClimbRecord(UserClimbTowerTopClimbRecord record) {
        if (null == record) {
            return;
        }
        synchronized (topClimbRecordList) {
            if (topClimbRecordList.size() >= GameConfig.ESTATE_WAR_MAX_RECORD_NUM) {
                topClimbRecordList.removeLast();
            }
            topClimbRecordList.addFirst(record);
        }
    }

    public ClimbTowerProto.ClimbTowerTopClimbRecordRespMsg.Builder getRecordListMsg() {
        ClimbTowerProto.ClimbTowerTopClimbRecordRespMsg.Builder respMsg = ClimbTowerProto.ClimbTowerTopClimbRecordRespMsg.newBuilder();
        respMsg.setRet(0);
        List<UserClimbTowerTopClimbRecord> tempRecordList = getRecordList();
        for (UserClimbTowerTopClimbRecord record : tempRecordList) {
            if (null == record) {
                continue;
            }
            ClimbTowerProto.ClimbTowerTopClimbRecordTemp.Builder recordBuilder = ClimbTowerProto.ClimbTowerTopClimbRecordTemp.newBuilder();
            recordBuilder.setEnemyUserId(record.getEnemyUserId());
            recordBuilder.setEnemyAbility(record.getEnemyAbility().toString());
            recordBuilder.setOldCellNum(record.getOldCellNum());
            recordBuilder.setNewCellNum(record.getNewCellNum());
            recordBuilder.setMyAbility(record.getAbility().toString());
            recordBuilder.setRecordTime(record.getRecordTime());
            if (record.getEnemyUserId() > 0) {
                recordBuilder.setEnemyBaseInfo(PlayerBasePb.parsePlayerBaseTempMsg(record.getEnemyBaseInfo()));
            }
            respMsg.addRecordList(recordBuilder);
        }
        return respMsg;
    }

    public void ConfirmLastDefeat(long recordTime) {
        if (recordTime >= userData.getLastDefeatedTime()) {
            userData.setLastDefeatedTime(recordTime);
        }
    }

    public UserClimbTowerTopClimbRecord getLastDefeatRecord() {
        List<UserClimbTowerTopClimbRecord> tempRecordList = getRecordList();
        for (UserClimbTowerTopClimbRecord record : tempRecordList) {
            if (null == record) {
                continue;
            }
            if (userData.getLastDefeatedTime() >= record.getRecordTime()) {
                break;
            }
            if (record.getOldCellNum() > record.getNewCellNum()) {
                //层数变低，被击败
                return record;
            }
        }
        return null;
    }

    public void updateUserAbility(BigInteger ability) {
        userData.setAbility(ability);
        //能力增加也要同步榜单
        player.notifyListener(eGamePlayerEventType.ClimbTowerCellNumCrossRank.getValue(),  new ValueParamArgs(userData.getCellNum(), String.valueOf(userData.getAbility())));

        if (userData.getTopCellNum() > 0) {
            player.sendPacket(Protocol.C_CLIMB_TOWER_UPDATE_TOP_ABILITY,
                    ClimbTowerProto.ClimbTowerCrossUpdateAbilityReqMsg.newBuilder().
                            setActivityId(userData.getActivityId()).
                            setAbility(userData.getAbility().toString()).
                            setTopCellNum(userData.getTopCellNum()));
        }
    }

}
